/*****************************************************************************
*
*  @file     FlashDriver.c
*  @brief    Flash驱动
*            1. 负责实现Flash驱动
*			 2. 提供数据存储和读取接口
*
*  @author   潘学林
*  @email                                        
*  @version  V0.000
*  @date     2022/4/13
*  @license  /
*----------------------------------------------------------------------------*
*  Remark         : Description                                              *
*----------------------------------------------------------------------------*
*  Change History :                                                          *
*  <Date>     | <Version> | <Author>       | <Description>                   *
*----------------------------------------------------------------------------*
*  2022/4/13  | 0.000     | 潘学林         | 创建文件                        *
*----------------------------------------------------------------------------*
*
*****************************************************************************/

/* Includes ------------------------------------------------------------------*/

#include "FlashDriver.h" 

/* Micros/Enumerate/Structures -----------------------------------------------*/

#define DIAG_ENABLE_INTERRUPT()         __asm ("CPSIE  I")
#define DIAG_DISABLE_INTERRUPT()        __asm ("CPSID  I")

/* Variables -----------------------------------------------------------------*/

/* 参数存储信息 */
static PARAMETER_STORE_INFO parameterStoreInfo; 

/* Functions -----------------------------------------------------------------*/

/*****************************************
* 内部函数
*****************************************/

/**
  * @brief  Flash参数初始化
  * @param  None
  * @retval None
  */
static void FlashDriver_ParameterInit(void)
{
    for (uint16 i=0; i<FLASH_STORE_DATA_LENGTH; i++)
    {
        parameterStoreInfo.writeDataInfo.data[i] = FLASH_STORE_DEFAULT_VALUE;
    }
    parameterStoreInfo.storeFlag = FALSE;
    parameterStoreInfo.writeState = FLASH_DRIVER_WRITE_STATE_IDLE;
}

/**
  * @brief  页擦除
  * @param  None
  * @retval None
  */
static void FlashDriver_PageErase(volatile uint32 startAddr)
{
	/* unlock the flash program/erase controller */
	fmc_unlock();

	/* clear all pending flags */
	fmc_flag_clear(FMC_FLAG_BANK0_END);
	fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
	fmc_flag_clear(FMC_FLAG_BANK0_PGERR);

#if 0
	/* page counter */
	uint32_t eraseCounter;
	
	/* erase the flash pages */
	for (eraseCounter = 0; eraseCounter < PAGE_NUM; eraseCounter++)
	{
		fmc_page_erase(FMC_WRITE_START_ADDR + (FMC_PAGE_SIZE * eraseCounter));
		fmc_flag_clear(FMC_FLAG_BANK0_END);
		fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
		fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
	}
#else
	fmc_page_erase(startAddr);
	fmc_flag_clear(FMC_FLAG_BANK0_END);
	fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
	fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
#endif

	/* lock the main FMC after the erase operation */
	fmc_lock();
}

/**
  * @brief  页编程
	* @param  startAddr 起始存储地址
	*				  dataAddr 待写入数据的首地址
	*					dataLength 数据长度（必须为4的整倍数）
  * @retval None
  */
static void FlashDriver_PageProgram(volatile uint32 startAddr,uint32 *dataAddr, uint16 dataLength)
{
	/* 页起始地址 */
	volatile static uint32 address = 0;
	
	/* unlock the flash program/erase controller */
	fmc_unlock();

    DIAG_DISABLE_INTERRUPT();
    
	/* 页起始地址，从起始地址开始写入数据 */
	address = startAddr;
	/* program flash */
	while (address < (startAddr + dataLength))
	{
		fmc_word_program(address, *dataAddr);
		address += 4;
		dataAddr++;
		fmc_flag_clear(FMC_FLAG_BANK0_END);
		fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
		fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
	}

    DIAG_ENABLE_INTERRUPT();
    
	/* lock the main FMC after the program operation */
	fmc_lock();
}

/**
  * @brief  从FLASH读数据
  * @note   从单片机内部FLASH中读出内容  
  * @param  addrShift, EEPROM 操作起始地址偏移
  *         dataAddr, 需要写入内容的缓冲区起始地址
  *         dataLength, 需要写入内容的长度，单位字节，必须为4的整数倍
  *         注，缓冲区地址不是4字节整数倍会出现硬件错误中断
  * @retval None
  */
static void FlashDriver_ReadBytes(uint32 startAddr, uint32 *dataAddr, uint16 dataLength)
{ 
	uint16 lengthByWord = (dataLength >> 2);
	volatile uint32 address = startAddr;
	
    DIAG_DISABLE_INTERRUPT();
    
	while (lengthByWord--)
	{
		*dataAddr++ = *(__IO uint32*)address;
		address += 4;
	}
    
    DIAG_ENABLE_INTERRUPT();
}

/**
* @brief  页擦除完成检测
* @param  None
* @retval None
*/
static BOOL FlashDriver_PageEraseFinishCheck(void)
{
	uint32 i;
	/* 擦除结果，默认擦除完成 */
	BOOL eraseResult = TRUE;
	/* 页起始地址 */
	volatile static uint32 *ptr = NULL;
	
	/* 页起始地址，从头开始检测是否所有的数据都被成功擦除（擦除完成后数据默认为0xFFFFFFFF） */
	ptr = (uint32 *)FMC_WRITE_START_ADDR;
	/* check flash whether has been erased */
	for (i = 0; i < ONE_PAGE_WORD_NUM; i++)
	{
		if(0xFFFFFFFF != (*ptr))
		{
			/* 擦除未完成 */
			eraseResult = FALSE;
			
			break;
		}
		else
		{
			ptr++;
		}
	}
	
	return eraseResult;
}

/**
  * @brief  写数据处理
  * @param  None
  * @retval None
  */
static void FlashDriver_WriteProcess(void)
{
    static uint32 sysTick = 0;
    
    /* 收到写数据请求 */
    if (parameterStoreInfo.storeFlag == TRUE)
    {
        switch (parameterStoreInfo.writeState)
        {
            case FLASH_DRIVER_WRITE_STATE_IDLE:
            {
                /* nop */
            }
            break;  

            case FLASH_DRIVER_WRITE_STATE_ERASE:
            {
                /* 页擦除 */
                FlashDriver_PageErase(FMC_WRITE_START_ADDR);
                /* 获取当前tick count */
                sysTick = delay_get_system_tick();
                
                parameterStoreInfo.writeState = FLASH_DRIVER_WRITE_STATE_WAIT;
            }
            break;
            
            case FLASH_DRIVER_WRITE_STATE_WAIT:
            {
                /* 等待擦除完成--超时则此次操作结束 */
                if ((delay_get_system_tick() - sysTick) < FLASH_ERASE_TIMEOUT)
                {
                    if (FlashDriver_PageEraseFinishCheck() == TRUE)
                    {
                        parameterStoreInfo.writeState = FLASH_DRIVER_WRITE_STATE_WRITE;
                    }
                    else
                    {
                        /* nop */
                    }
                }
                else
                {
                    parameterStoreInfo.writeState = FLASH_DRIVER_WRITE_STATE_IDLE;
                }
            }
            break;
            
            case FLASH_DRIVER_WRITE_STATE_WRITE:
            {
                /* 写入新数据 */
                FlashDriver_PageProgram(FMC_WRITE_START_ADDR,&parameterStoreInfo.writeDataInfo.data[0],sizeof(PARAMETER_STORE_DATA));
                /* 此次写数据流程结束 */
                parameterStoreInfo.storeFlag = FALSE;
                
                parameterStoreInfo.writeState = FLASH_DRIVER_WRITE_STATE_IDLE;
            }
            break;
            
            case FLASH_DRIVER_WRITE_STATE_END:
            {
                /* nop */
            }
            break;
            
            default:
            {
                /* nop */
            }
            break;
        }
    }
    else
    {
        /* nop */
    }
}

/*****************************************
* 接口函数
*****************************************/
/**
  * @brief  Flash驱动初始化
  * @param  None
  * @retval None
  */
void FlashDriver_Init(void)
{
	/* 1. Flash初始化 */
    FlashDriver_ParameterInit();
    
#ifdef IF_ENABLE_FLASH_SELF_TEST	
	/* 2. Flash自测 */
    FlashDriver_SelfTest();
#endif
}

/**
  * @brief  Flash轮询任务
  * @param  None
  * @retval None
  */
void FlashDriver_PollTask(void)
{
    /* 1. 写数据处理 */
	FlashDriver_WriteProcess();
}

/**
  * @brief  写数据
  * @param  datPtr 数据指针，length 数据长度
  * @retval 写入结果，0：写入成功 1：写入失败
  */
uint8 FlashDriver_WriteData(uint8 *datPtr, uint16 length)  
{
	uint8 retValue = 1;
    uint8 *dataBuffPtr = NULL;
	
    /* 地址和长度检测 */
    if ((datPtr == NULL) || (length > sizeof(PARAMETER_STORE_DATA)))
    {
        retValue = 1;
    }
    else
    {
        /*
		 * 1. 拷贝数据
		 */
		/* 初始化缓冲区 */
		memset((uint8*)&parameterStoreInfo.writeDataInfo.data[0],(uint8)FLASH_STORE_DEFAULT_VALUE,sizeof(PARAMETER_STORE_DATA));
		/* 取存储缓冲区的首地址 */
		dataBuffPtr = (uint8*)&parameterStoreInfo.writeDataInfo.data[0];
		/* 将待存储数据拷贝至存储缓冲区 */
		for (uint16 i=0; i<length; i++)
		{
			*dataBuffPtr = *datPtr;
			datPtr++;
			dataBuffPtr++;
		}
		
		/*
		 * 2. 置位存储标志、设置状态为擦除
		 */
		parameterStoreInfo.storeFlag = TRUE;
		parameterStoreInfo.writeState = FLASH_DRIVER_WRITE_STATE_ERASE;
		
		retValue = 0;
    }

    return retValue;
}

/**
  * @brief  读数据
  * @param  datPtr 数据指针，length 数据长度
  * @retval 读取结果，0：读取成功 1：读取失败
  */
uint8 FlashDriver_ReadData(uint8 *datPtr, uint16 length) 
{
	uint8 retValue = 1;
    uint8 *dataBuffPtr = NULL;
    uint32 readDataBuff[FLASH_STORE_DATA_LENGTH];
    
    /* 地址、数据长度、写入状态（写入流程执行完成后才允许读取）检测 */
    if ((datPtr == NULL) || (length > sizeof(PARAMETER_STORE_DATA)) || (parameterStoreInfo.writeState != FLASH_DRIVER_WRITE_STATE_IDLE))
    {
        retValue = 1;
    }
    else
    {
        /*
		 * 1. 读取数据
		 */
		/* 初始化缓冲区 */
		memset((uint8*)&readDataBuff[0],(uint8)FLASH_STORE_DEFAULT_VALUE,sizeof(PARAMETER_STORE_DATA));
		/* 读取数据 */
		FlashDriver_ReadBytes(FMC_WRITE_START_ADDR,&readDataBuff[0],sizeof(PARAMETER_STORE_DATA));
		
		/*
		 * 2. 将数据拷贝给USER
		 */
		/* 取存储缓冲区的首地址 */
		dataBuffPtr = (uint8*)&readDataBuff[0];
		/* 将读取出来的数据拷贝给USER */
		for (uint16 i=0; i<length; i++)
		{
			*datPtr = *dataBuffPtr;
			datPtr++;
			dataBuffPtr++;
		}
		
		retValue = 0;
    }
    
    return retValue;
}

/**
  * @brief  存储自测
  * @param  None
  * @retval None
  */
BOOL FlashDriver_SelfTest(void)
{
    /* 读取数据 */
	uint32 readData[2] = {0, 0};
	/* 存储数据 */
	uint32 writeData[2] = {0x12345678, 0x87654321};
	
	/* 存数据 */
	FlashDriver_WriteData((uint8*)&writeData[0], sizeof(writeData));
    
    do
    {
        /* 写数据处理 */
        FlashDriver_PollTask();
        /* 读数据 */
        FlashDriver_ReadData((uint8*)&readData[0], sizeof(readData));
    }
    while((readData[0] != 0x12345678) && (readData[1] != 0x87654321));
	
    return TRUE;
}

/********************************* END OF FILE ********************************/

